/*
 * Copyright 2014 JootMir Project
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * Support: http://www.jootmir.org
 */
package org.jootmir.client.game;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import org.apache.log4j.Logger;
import org.jootmir.client.core.Files;
import org.jootmir.client.core.Graphics;
import org.jootmir.client.core.exception.JMir2Exception;
import org.jootmir.client.core.texture.loader.TextureLoaderHandler;
import org.jootmir.client.core.util.AbstractBundle;
import org.jootmir.client.core.util.Kit;
import org.jootmir.client.game.Wils.WILImageInfo;

/**
 * WIL图片加载信息
 * 
 * @author ShawRyan
 */
public class WILImageLoaderHandler extends AbstractBundle implements TextureLoaderHandler {
	/** log */
	private static Logger log = Logger.getLogger(WILImageLoaderHandler.class);

	private Integer index;
	private volatile int width;
	private volatile int height;

	/**
	 * 真正用于纹理加载的方法 <br>
	 * 此方法返回字节数组，字节数组为RGBA格式的色彩数据 <br>
	 * 在整个程序中实际上只有这个函数是<b>另起线程</b>，是<b>异步</b>的。所以在这个方法里不能使用{@link GL11 GL}
	 * 的函数，因为线程内没有{@link GLContext context} <br>
	 * 
	 * @return 纹理数据<br>
	 *         此数据为直接分配物理内存的指针，便于显卡读取
	 */
	@Override
	public ByteBuffer call() throws Exception {
		int textureType = (index & 0xff000000) >> 24;
		int textureFileIndex = (index & 0xff0000) >> 16;
		int textureIndex = index & 0xffff;
		RandomAccessFile raf = null;
		{
			WILImageInfo wii = null;
			switch (textureType) {
			case Wils.TEXTURE_TYPE_TILES:
				raf = Files.randomAccessFile("/data/Tiles.wil");
				wii = Wils.get(textureIndex, "/data/Tiles.wil");
				break;
			case Wils.TEXTURE_TYPE_SMTILES:
				raf = Files.randomAccessFile("/data/SmTiles.wil");
				wii = Wils.get(textureIndex, "/data/SmTiles.wil");
				break;
			case Wils.TEXTURE_TYPE_OBJECTS:
				raf = Files
						.randomAccessFile("/data/Objects" + (textureFileIndex == 0 ? "" : textureFileIndex) + ".wil");
				wii = Wils.get(textureIndex,
						"/data/Objects" + (textureFileIndex == 0 ? "" : textureFileIndex) + ".wil");
				break;
			default:
				break;
			}

			width = wii.getWidth();
			height = wii.getHeight();
			putIntExtra("dataStart", wii.getDataStart());
			putIntExtra("dataSize", wii.getDataSize());
			putByteExtra("colorCount", wii.getColorCount());
			putShortExtra("offsetX", wii.getOffsetX());
			putShortExtra("offsetY", wii.getOffsetY());
		}

		int offset = getIntExtra("dataStart");
		int length = getIntExtra("dataSize");

		// 兼容老显卡，一般来说版本大于或等于OpenGL2.0的显卡都支持非2的幂次宽高纹理
		int nWidth = width;
		int nHeight = height;
		if (!Graphics.get().isNonpoweroftwoSupport()) {
			if (!Kit.isPowerOfTwo(width))
				width = Kit.closestPowerOfTwo(width);
			if (!Kit.isPowerOfTwo(height))
				height = Kit.closestPowerOfTwo(height);
		}

		// 创建字节缓存，使用直接分配内存方式
		ByteBuffer unpackedPixels = ByteBuffer.allocateDirect(width * height * 4);
		unpackedPixels.order(ByteOrder.nativeOrder());

		if (length < 13) {
			// 如果是空白图片
			for (int i = 0; i < width * height; ++i) {
				unpackedPixels.put(SDK.palletes[0][1]);
				unpackedPixels.put(SDK.palletes[0][2]);
				unpackedPixels.put(SDK.palletes[0][3]);
				unpackedPixels.put(SDK.palletes[0][0]);
			}
		} else {
			byte[] pixels = new byte[length];
			try {
				raf.seek(offset + 8);
				raf.read(pixels);
			} catch (IOException ex) {
				JMir2Exception exception = JMir2Exception.valueOf(ex, JMir2Exception.EXCEPTION_TYPE_FILESTREAM);
				log.error(exception.getMessage(), ex);
				throw exception;
			}
			if (getByteExtra("colorCount") == 8) {
				int p_index = 0;
				for (int h = height - 1; h >= height - nHeight; --h)
					for (int w = width - nWidth; w < width; ++w) {
						// 跳过填充字节
						if (w == width - nWidth)
							p_index += Kit.skipBytes(8, nWidth);
						// 坐标转换，bmp中图片数据是从左到右，从下到上，而我们需要从下到上
						unpackedPixels.put((h * width + w) * 4, SDK.palletes[pixels[p_index] & 0xff][1]);
						unpackedPixels.put((h * width + w) * 4 + 1, SDK.palletes[pixels[p_index] & 0xff][2]);
						unpackedPixels.put((h * width + w) * 4 + 2, SDK.palletes[pixels[p_index] & 0xff][3]);
						unpackedPixels.put((h * width + w) * 4 + 3, SDK.palletes[pixels[p_index++] & 0xff][0]);
					}
			} else if (getByteExtra("colorCount") == 16) {
				int p_index = 0;
				for (int h = height - 1; h >= height - nHeight; --h)
					for (int w = width - nWidth; w < width; ++w, p_index += 2) {
						// 跳过填充字节
						if (w == width - nWidth)
							p_index += Kit.skipBytes(16, nWidth);
						// 坐标转换，bmp中图片数据是从左到右，从下到上，而我们需要从下到上
						// 获取短整型的色彩数据(565压缩过)
						if (pixels[p_index + 1] == 0 && pixels[p_index] == 0) {
							// 暂时不手动填充，因为默认分配内存即为0
						} else {
							unpackedPixels.put((h * width + w) * 4, (byte) (pixels[p_index + 1] & 0xF8));
							unpackedPixels.put((h * width + w) * 4 + 1,
									(byte) (((pixels[p_index + 1] & 0x7) << 5) | ((pixels[p_index] & 0xE0) >> 3)));
							unpackedPixels.put((h * width + w) * 4 + 2, (byte) ((pixels[p_index] & 0x1F) << 3));
							unpackedPixels.put((h * width + w) * 4 + 3, (byte) 255);
						}
					}
			}
		}

		// fix LWJGL org.lwjgl.BufferChecks#checkBuffer
		unpackedPixels.position(0);

		return unpackedPixels;
	}

	@Override
	public void fromIndexRef(Integer ref) {
		this.index = ref;
	}

	@Override
	public int getWidth() {
		return width;
	}

	@Override
	public int getHeight() {
		return height;
	}

}